#ifndef __M_EXCHANGE_H__
#define __M_EXCHANGE_H__

#include "../MQcommon/helper.hpp"
#include "../MQcommon/mq_msg.pb.h"
#include"../MQcommon/logger.hpp"

#include <google/protobuf/map.h>
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace bitmq{
    struct ExChange{
        //交换机名称
        std::string name;
        //交换机类型
        ExchangeType type;
        //交换机持久化标志
        bool durable;
        //是否自动删除标志
        bool auto_delete;
        //其他参数
        google::protobuf::Map<std::string,std::string> args;
        //其他参数的形式:key=value&key=value......
        using ptr =std::shared_ptr<ExChange>;
        ExChange() {}
        ExChange(const std::string &ename, 
            ExchangeType etype, 
            bool edurable,
            bool eauto_delete,
            const google::protobuf::Map<std::string, std::string> &eargs):
            name(ename), type(etype), durable(edurable), 
            auto_delete(eauto_delete), args(eargs) {}
        
        void setArgs(const std::string& target){
            std::vector<std::string> str_arrgy;
            int pos=0;
            std::string key;
            std::string value;
            if(!target.empty()){
                bitmq::StrHelper::stringSpilt(target,"&",str_arrgy);
            }
            for(auto& x:str_arrgy){
                pos=value.find("=");
                if(pos==std::string::npos){
                    return ;
                }
                key=x.substr(0,pos);
                value=x.substr(pos+1);
                args[key]=value;
            }
        }

        std::string  getArgs(){
            std::string result;
            for(auto& value:args){
              result=result+value.first+"="+value.second;
              result+="&";
           }
           return result;
        }
    };
    using ExchangeMap=std::unordered_map<std::string,ExChange::ptr>; 
class ExchangeMapper{
    public:
    ExchangeMapper(const std::string dbfile):_helper(dbfile){
        std::string path=FileHelper::parentDirectory(dbfile);
        FileHelper::createDirectory(path);
        _helper.open();
        createTable();
    }
    void createTable(){
        std::stringstream river;
        river<<"create table if not exists exchange_table";
        river<<"(name varchar(32) primary key,type int,durable int,auto_delete int,args varchar(128));";
        bool ret=_helper.exec(river.str(),nullptr,nullptr);
        if(ret == false){
            DLOG("创建表[%s]失败","exchange_table");
            abort();
        }
    }
    void deleteTbale(){
        #define DELETE_TABLE "drop table if exists exchange_table;"
        bool ret=_helper.exec(DELETE_TABLE,nullptr,nullptr);
        if(ret == false){
            DLOG("删除表[exchange_table]失败");
            abort();
        }
    }
    bool insert(ExChange::ptr& exp){
      std::stringstream river;
      river<<"insert into exchange_table values(";
      river<<"'"<<exp->name<<"',";
      river<<exp->type<<",";
      river<<exp->durable<<",";
      river<<exp->auto_delete<<",";
      river<<"'"<<exp->getArgs()<<"')";
      bool ret=_helper.exec(river.str(),nullptr,nullptr);
      if(ret == false){
        DLOG("插入数据失败,文件:[%s]","exchange_teble");
        return false;
      }
      return true;
    }
    bool remove(const std::string& ename){
        std::stringstream river;
        river<<"delete from exchange_table where name=";
        river<<"'"<<ename<<"';";
        bool ret=_helper.exec(river.str(),nullptr,nullptr);
        if(ret == false){
            DLOG("删除数据失败,文件:[%s]","exchange_table");
            return false;
        }
        return true;
    }
    //查询语句，需要保存查询结果
    ExchangeMap recovery(){
        std::stringstream river;
        ExchangeMap result;
        river<<"select name, type, durable, auto_delete, args from exchange_table;";
        bool ret=_helper.exec(river.str(),selectCallBack,&result);
        if(ret == false){
            ELOG("获取交换机表失败！");
            return ExchangeMap();
        }
        return result;
    }
    private:
    static int selectCallBack(void* args,int count,char** row,char** fields){
        ExchangeMap *result = (ExchangeMap *)args;
        auto exp = std::make_shared<ExChange>();
        exp->name = row[0];
        exp->type = (bitmq::ExchangeType)std::stoi(row[1]);
        exp->durable = (bitmq::DeliverMode)std::stoi(row[2]);
        exp->auto_delete = (bool)std::stoi(row[3]);
        if (row[4])
            exp->setArgs(row[4]);
        result->insert(std::make_pair(exp->name, exp));
        return 0;
    }
    Sqlite3Helper _helper;
};
class ExchangeManager{
    public:
    using ptr = std::shared_ptr<ExchangeManager>;
    ExchangeManager(const std::string& dbfile):_helper(dbfile){
        _emap=_helper.recovery();
    }
    bool declareExchange(const std::string &name,
        ExchangeType type, bool durable, bool auto_delete,
        const google::protobuf::Map<std::string, std::string> &args){
            //是否已经有这个交换机存在
           auto it=_emap.find(name);
           if(it!=_emap.end()){
               DLOG("该交换机[%s]已经存在！",name.c_str());
               return true;
           }
           auto exp=std::make_shared<ExChange>(name,type,durable,auto_delete,args);
           if(exp->durable==DURABLE){
            _helper.insert(exp);
           }
           _emap[name]=exp;
           return true;
        }
    //删除交换机
    void deleteExchange(const std::string &name){
         if(_emap.empty()){
            return ;
         }
         auto it=_emap.find(name);
         if(it == _emap.end()){
            DLOG("删除的交换机[%s]不存在",name.c_str());
            return ;
         }
         bool ret=_helper.remove(name);
         if(ret != true){
            DLOG("文件中删除交换机[%s]失败",name.c_str());
            return ;
         }
         _emap.erase(name);
    }
     //获取指定交换机对象
    ExChange::ptr selectExchange(const std::string &name){
        auto it=_emap.find(name);
        if(it == _emap.end()){
           DLOG("指定的交换机[%s]不存在",name.c_str());
           return ExChange::ptr();
        }
        return _emap[name];
    }
    //判断交换机是否存在
    bool exists(const std::string &name){
        auto it=_emap.find(name);
        if(it == _emap.end()){
           DLOG("指定的交换机[%s]不存在",name.c_str());
           return false;
        }
        return true;
    }
    size_t size(){
        return _emap.size();
    }
    void clear(){
        _helper.deleteTbale();
        _emap.clear();
    }  
    private:
    std::mutex _mutex;
    ExchangeMapper _helper;
    ExchangeMap _emap;
};
}
#endif